#include "logger.hpp"
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>

namespace ken_im
{
typedef websocketpp::server<websocketpp::config::asio> server_t;
// 连接的类型： server_t::connection_ptr

/**
 * @class Connection
 * @brief Connection 类用于管理客户端的长连接信息。
 *
 * Connection
 * 类提供了一种方式来存储和管理客户端的长连接信息。它通过两个映射表来维护用户ID和连接指针之间的关系，
 * 以及连接指针和客户端信息（用户ID和SSID）之间的关系。类中的方法提供了插入、查询、获取和删除连接信息的功能。
 *
 * @details
 * Connection 类包含一个嵌套的 Client
 * 结构体，用于存储客户端的用户ID和SSID。类使用两个 unordered_map
 * 来存储连接信息：
 * - _uid_connections：键为用户ID，值为连接指针。
 * - _conn_clients：键为连接指针，值为 Client 结构体。
 *
 * 类的核心功能包括：
 * - insert：插入新的连接信息。
 * - connection：根据用户ID查询连接指针。
 * - client：根据连接指针获取客户端信息。
 * - remove：删除连接信息。
 *
 * 使用示例：
 * @code
 * Connection conn;
 * server_t::connection_ptr connPtr = ...; // 获取连接指针
 * std::string uid = "user123";
 * std::string ssid = "session456";
 * conn.insert(connPtr, uid, ssid); // 插入连接信息
 * server_t::connection_ptr retrievedConn = conn.connection(uid); //
 * 查询连接信息 std::string retrievedUid, retrievedSsid;
 * conn.client(retrievedConn, retrievedUid, retrievedSsid); // 获取客户端信息
 * conn.remove(retrievedConn); // 删除连接信息
 * @endcode
 *
 * @note
 * - 所有对连接信息的操作都是线程安全的，因为使用了互斥锁（std::mutex）。
 * - 如果尝试获取或删除不存在的连接信息，将会记录错误日志。
 */
class Connection
{
  public:
    struct Client
    {
        Client( const std::string &u, const std::string &s )
            : uid( u ), ssid( s )
        {
        }
        std::string uid;
        std::string ssid;
    };
    using ptr = std::shared_ptr<Connection>;
    Connection()
    {
    }
    ~Connection()
    {
    }
    // 插入新的连接信息
    void insert( const server_t::connection_ptr &conn, const std::string &uid,
                 const std::string &ssid )
    {
        std::unique_lock<std::mutex> lock( _mutex );
        _uid_connections.insert( std::make_pair( uid, conn ) );
        _conn_clients.insert( std::make_pair( conn, Client( uid, ssid ) ) );
        LOG_DEBUG( "新增长连接用户信息：{}-{}-{}", (size_t) conn.get(), uid,
                   ssid );
    }

    // 根据用户 ID 查找连接
    server_t::connection_ptr connection( const std::string &uid )
    {
        std::unique_lock<std::mutex> lock( _mutex );
        auto it = _uid_connections.find( uid );
        if ( it == _uid_connections.end() )
        {
            LOG_ERROR( "未找到 {} 客户端的长连接！", uid );
            return server_t::connection_ptr();
        }
        LOG_DEBUG( "找到 {} 客户端的长连接！", uid );
        return it->second;
    }

    // 根据连接指针获取客户端信息
    bool client( const server_t::connection_ptr &conn, std::string &uid,
                 std::string &ssid )
    {
        std::unique_lock<std::mutex> lock( _mutex );
        auto it = _conn_clients.find( conn );
        if ( it == _conn_clients.end() )
        {
            LOG_ERROR( "获取-未找到长连接 {} 对应的客户端信息！",
                       (size_t) conn.get() );
            return false;
        }
        uid = it->second.uid;
        ssid = it->second.ssid;
        LOG_DEBUG( "获取长连接客户端信息成功！" );
        return true;
    }

    //  删除连接信息
    void remove( const server_t::connection_ptr &conn )
    {
        std::unique_lock<std::mutex> lock( _mutex );
        auto it = _conn_clients.find( conn );
        if ( it == _conn_clients.end() )
        {
            LOG_ERROR( "删除-未找到长连接 {} 对应的客户端信息！",
                       (size_t) conn.get() );
            return;
        }
        _uid_connections.erase( it->second.uid );
        _conn_clients.erase( it );
        LOG_DEBUG( "删除长连接信息完毕！" );
    }

  private:
    std::mutex _mutex;

    // 存储 用户 ID（uid） → WebSocket 连接指针 的映射，方便通过用户
    // ID查找连接。
    std::unordered_map<std::string, server_t::connection_ptr> _uid_connections;

    // 存储 WebSocket 连接指针 → 客户端信息（uid + ssid）
    // 的映射，方便通过连接获取用户信息。
    std::unordered_map<server_t::connection_ptr, Client> _conn_clients;
};
} // namespace ken_im